/*
 This program is submitted as part of an assignment in the
 J2E
 Fall Semester 2010-2011 
 School of Computer Science
 Interdisciplinary Center, Hertzelia, Israel 

 http://www.idc.ac.il 

 Exercise No.         : 3
 File Name            : BaseActivity.java
 Names (First Last)   : Itay Sorani, Nadav Ziv, Yonathan Zarsky
 Student No.          : 066530254, 039937883, 039692918
 */

package com.example.communication;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import com.example.TaskResult;
import com.example.communication.json.JSONArray;
import com.example.communication.json.JSONObject;
import com.example.models.Building;
import com.example.models.Unit;
import com.example.models.Towers.ArrowTower;
import com.example.util.Figure;
import com.example.util.FigureType;
import com.example.util.GameModel;
import com.example.util.Vec2D;

/**
 * A ResultMarshaller that marshal result objects using a binary format
 */
public class ResultMarshallerJson implements ResultMarshaller {

    private static final String SUCCESS_PROPERTY = "success";
    private static final String FIGURES_PROPERTY = "figuresCount";
    private static final String ERROR_MESSAGE_PROPERTY = "errorMessage";
	private static final String FIGURE_TYPE_PROPERTY = "figureType";
	private static final String FIGURE_X_POSITION_PROPERTY = "xPositon";
	private static final String FIGURE_Y_POSITION_PROPERTY = "yPosition";
	private static final String FIGURE_ARRAY_PROPERTY = "figuresArray";
	private static final String FIGURE_DIRECTION_X_PROPERTY = "xDirection";
	private static final String FIGURE_DIRECTION_Y_PROPERTY = "yDirection";
	private static final String FIGURE_NAME_PROPERTY = "figureName";
	private static final String FIGURE_VELOCITY_PROPERTY = "velocity";
	private static final String PLAYER_HITPOINTS_PROPERTY = "playerHitPoints";
	private static final String ENEMY_HITPOINTS_PROPERTY = "enemyHitPoints";
	private static final String PLAYER_POINTS_PROPERTY = "playerPoints";
	private static final String STRINGS_PROPERTY = "points";
	private static final String MESSAGE_TO_DISPLAY_PROPERTY = "messageToDisplay";
	private static final String IS_CANVAS_MOVING_PROPERTY = "isCanvasMoving";
	private static final String X_CANVAS_MOVE_DESTINATION_PROPERTY = "xCanvasMoveDestination";
	private static final String Y_CANVAS_MOVE_DESTINATION_PROPERTY = "yCanvasMoveDestination";
	private static final String CANVAS_MOVEMENT_PROPERTY = "canvasMovement";
    
    /**
     * Writes a given MoveResult on a given output stream in a way that it can be reproduced at the other hand
     * using a call to unmarshal(DataInputStream)
     */
    public void marshal(DataOutputStream output, TaskResult result) throws IOException {
        JSONObject json = convertToJson(result);
        String jsonString = json.toString();
        output.writeUTF(jsonString);
        //System.out.println("Writing: " + jsonString);
    }
    
    /**
     * Reads from an input stream a MoveRequest object that was written using the marshal(OutputStream) method
     */
    public TaskResult unmarshal(DataInputStream input) throws IOException {
        String jsonString = input.readUTF();
        JSONObject json = new JSONObject(jsonString);
        return resolveJson(json);
    }

    private JSONObject convertToJson(TaskResult result) {
    	boolean success = result.getErrorMessage() == null;
        JSONObject json = new JSONObject();
        json.put(SUCCESS_PROPERTY, success);
        if (success) {
            GameModel model = result.getModel();
            int numberOfFigures = model.getNumOfModels();
            JSONObject jsonMoveCanvas = new JSONObject();
            jsonMoveCanvas.put (IS_CANVAS_MOVING_PROPERTY,result.isCanvasMoving());
            jsonMoveCanvas.put (X_CANVAS_MOVE_DESTINATION_PROPERTY,result.getxCanvasMoveDestination());
            jsonMoveCanvas.put (Y_CANVAS_MOVE_DESTINATION_PROPERTY,result.getyCanvasMoveDestination());
            json.put(CANVAS_MOVEMENT_PROPERTY,jsonMoveCanvas);
            JSONObject jsonStrings = new JSONObject();
            jsonStrings.put(PLAYER_POINTS_PROPERTY, result.getPlayerPoints());
            jsonStrings.put(PLAYER_HITPOINTS_PROPERTY, result.getPlayerHitPoints());
            jsonStrings.put(ENEMY_HITPOINTS_PROPERTY, result.getEnemyHitPoints());
            jsonStrings.put(MESSAGE_TO_DISPLAY_PROPERTY, result.getMessageToDisplay());
            json.put(STRINGS_PROPERTY,jsonStrings);
            json.put(FIGURES_PROPERTY, numberOfFigures);
            JSONArray figures = new JSONArray();
            for (int i = 0; i < numberOfFigures; i++) {
            	Figure figure = model.getModel(i);
            	JSONObject figureToPut = new JSONObject();
            	figureToPut.put(FIGURE_TYPE_PROPERTY,figure.getFigureType().toString());
            	figureToPut.put(FIGURE_NAME_PROPERTY,figure.getName());
            	figureToPut.put(FIGURE_X_POSITION_PROPERTY,figure.getX());
            	figureToPut.put(FIGURE_Y_POSITION_PROPERTY,figure.getY());
            	figureToPut.put(FIGURE_DIRECTION_X_PROPERTY,figure.getDirection().getX());
            	figureToPut.put(FIGURE_DIRECTION_Y_PROPERTY,figure.getDirection().getY());
            	figureToPut.put(FIGURE_VELOCITY_PROPERTY,figure.getVelocity());
            	figures.put(figureToPut);
            }
            json.put(FIGURE_ARRAY_PROPERTY, figures);
        }
        else {
            json.put(ERROR_MESSAGE_PROPERTY, result.getErrorMessage());
        }
        return json;
    }

    protected TaskResult resolveJson(JSONObject json) {
    	TaskResult result = new TaskResult();
        boolean success = json.getBoolean(SUCCESS_PROPERTY);
        if (success) {
        	JSONObject jsonMoveCanvas = json.getJSONObject(CANVAS_MOVEMENT_PROPERTY);
        	boolean isCanvasMoving = jsonMoveCanvas.getBoolean(IS_CANVAS_MOVING_PROPERTY);
        	float xCanvasMoveDestination = (float)jsonMoveCanvas.getDouble(X_CANVAS_MOVE_DESTINATION_PROPERTY);
        	float yCanvasMoveDestination = (float)jsonMoveCanvas.getDouble(Y_CANVAS_MOVE_DESTINATION_PROPERTY);
        	JSONObject jsonPoints = json.getJSONObject(STRINGS_PROPERTY);
        	int playerPoints = jsonPoints.getInt(PLAYER_POINTS_PROPERTY);
            int playerHitPoints = jsonPoints.getInt(PLAYER_HITPOINTS_PROPERTY);
            int enemyHitPoints = jsonPoints.getInt(ENEMY_HITPOINTS_PROPERTY);
            String messageToDisplay = jsonPoints.getString(MESSAGE_TO_DISPLAY_PROPERTY);
        	int numberOfFigures = json.getInt(FIGURES_PROPERTY);
        	JSONArray figures = json.getJSONArray(FIGURE_ARRAY_PROPERTY);
            GameModel gameModel = new GameModel();
            for (int i = 0; i < numberOfFigures; i++) {
            	JSONObject jsonFigure = figures.getJSONObject(i);
            	FigureType figureType = FigureType.valueOf(jsonFigure.getString(FIGURE_TYPE_PROPERTY));
            	String name = jsonFigure.getString(FIGURE_NAME_PROPERTY);
            	Vec2D position = new Vec2D((float)jsonFigure.getDouble(FIGURE_X_POSITION_PROPERTY),(float)jsonFigure.getDouble(FIGURE_Y_POSITION_PROPERTY));
            	Vec2D direction = new Vec2D((float)jsonFigure.getDouble(FIGURE_DIRECTION_X_PROPERTY),(float)jsonFigure.getDouble(FIGURE_DIRECTION_Y_PROPERTY));
            	float velocity = (float)jsonFigure.getDouble(FIGURE_VELOCITY_PROPERTY);
            	Figure figure = null;
            	switch (figureType) {
            		case building:
            			figure = new Building();
            			break;
            		case tower:
            			figure = new ArrowTower(null);
            			break;
            		case unit:
            			figure = new Unit();
            			break;
            		case simpleFigure:
            			figure = new Figure();
            			break;
            		case general:
            			figure = new Figure();
            			break;
            		case Shot:
            			figure = new Figure();
            			break;
            			
            	}
            	figure.setFigureType(figureType);
            	figure.setName(name);
            	figure.setPosition(position.getX(),position.getY());
            	figure.setDirection(direction);
            	figure.setVelocity(velocity);
            	gameModel.addFigure(figure);
            }
            result.setPlayerPoints(playerPoints);
            result.setPlayerHitPoints(playerHitPoints);
            result.setEnemyHitPoints(enemyHitPoints);
            result.setMessageToDisplay(messageToDisplay);
            result.setModel(gameModel);
            result.setCanvasMoving(isCanvasMoving);
            result.setxCanvasMoveDestination(xCanvasMoveDestination);
            result.setyCanvasMoveDestination(yCanvasMoveDestination);
        }
        else {
            result.setErrorMessage(json.getString(ERROR_MESSAGE_PROPERTY));
        }
        return result;
    }
}
